home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
-
- search.c
-
- This module handles the "Search" command.
-
- Copyright © 1994-1995, Northwestern University.
-
- ----------------------------------------------------------------------------*/
-
- #include <string.h>
- #include <ctype.h>
- #include <stdio.h>
-
- #include "glob.h"
- #include "search.h"
- #include "dialog.h"
- #include "newswatcher.h"
- #include "mark.h"
- #include "menus.h"
- #include "news.h"
- #include "group.h"
- #include "popuputil.h"
- #include "subscribe.h"
- #include "status.h"
- #include "memutil.h"
- #include "strutil.h"
- #include "header.h"
- #include "full.h"
-
-
-
- #define kSearchDlg 140 /* Search dialog */
- #define kSearchHeader 3
- #define kSearchPattern 4
- #define kSearchPopup 5
-
-
-
- /*----------------------------------------------------------------------------
- DoSearchDialog
-
- Present the search dialog.
-
- Exit: function result = error code.
- header = header name.
- pattern = search string.
- ----------------------------------------------------------------------------*/
-
- static OSErr DoSearchDialog (CStr255 header, CStr255 pattern)
- {
- static CStr255 headerSave = "";
- static CStr255 patternSave = "";
- DialogPtr dlg = nil;
- short item;
- OSErr err = noErr;
-
- if (*headerSave == 0) GetCString(kStrDefaultSearchHdr, headerSave);
-
- err = MyGetNewDialog(kSearchDlg, ok, cancel, &dlg);
- if (err != noErr) return err;
- RestoreMovableModalDialogPosition(dlg, gPrefs.searchLoc);
-
- strcpy(header, headerSave);
- strcpy(pattern, patternSave);
-
- DlgSetCString(dlg, kSearchHeader, header);
- SetItemKeyword(dlg, kSearchHeader);
- SetItemMaxLength(dlg, kSearchHeader, 255);
- DlgSetCString(dlg, kSearchPattern, pattern);
- SetItemMaxLength(dlg, kSearchPattern, 255);
- SelectDialogItemText(dlg, kSearchPattern, 0, 255);
- SetItemPopupTypeinItem(dlg, kSearchPopup, kSearchHeader);
-
- do {
- DlgEnableItem(dlg, ok, *header != 0 && *pattern != 0);
- MyMovableModalDialog(dlg, DialogFilter, &item);
- switch (item) {
- case kSearchPopup:
- case kSearchHeader:
- DlgGetCString(dlg, kSearchHeader, header);
- break;
- case kSearchPattern:
- DlgGetCString(dlg, kSearchPattern, pattern);
- break;
- }
- } while (item != ok && item != cancel);
-
- SaveMovableModalDialogPosition(dlg, &gPrefs.searchLoc);
- err = DoClose(dlg);
- if (err != noErr) return err;
-
- if (item == cancel) return userCanceledErr;
-
- strcpy(headerSave, header);
- strcpy(patternSave, pattern);
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- SearchOneGroup
-
- Search a single group.
-
- Entry: header = name of the header to be searched.
- pattern = search string.
- *theGroup = group record.
-
- Exit: function result = error code.
- theGroup->numUnread = number of matched articles.
- theGroup->unread = handle to unread list.
- ----------------------------------------------------------------------------*/
-
- static OSErr SearchOneGroup (char *header, char *pattern, TGroup *theGroup)
- {
- CStr255 groupName, statusStr;
- THeader **headers = nil;
- short numHeaders;
- THeader *pHeader, *pHeaderEnd;
- long firstUnread, lastUnread;
- long number;
- OSErr err = noErr;
- Boolean groupExists;
-
- strcpy(groupName, *gGroupNames + theGroup->nameOffset);
-
- GetCString(kStrSearchingStatusMsg, statusStr);
- strcat(statusStr, groupName);
- err = DisplayStatusMessage(statusStr);
- if (err != noErr) return err;
-
- err = GetGroupArticleRange(theGroup, &groupExists);
- if (err != noErr) return err;
- if (!groupExists) return noErr;
-
- theGroup->numUnread = 0;
- err = SearchHeaders(groupName, header, theGroup->firstMess,
- theGroup->lastMess, pattern, &headers, &numHeaders);
- if (err != noErr) return err;
- if (headers == nil) return noErr;
-
- MyHLock(headers);
- pHeaderEnd = *headers + numHeaders;
- firstUnread = 0;
- for (pHeader = *headers; pHeader < pHeaderEnd; pHeader++) {
- number = pHeader->number;
- if (firstUnread == 0) {
- firstUnread = lastUnread = number;
- } else if (pHeader->number == lastUnread+1) {
- lastUnread = number;
- } else {
- err = AppendUnreadRange(firstUnread, lastUnread, theGroup);
- if (err != noErr) goto exit;
- firstUnread = lastUnread = number;
- }
- }
- if (firstUnread != 0) {
- err = AppendUnreadRange(firstUnread, lastUnread, theGroup);
- if (err != noErr) goto exit;
- }
- MyDisposeHandle(headers);
- return noErr;
-
- exit:
-
- MyDisposeHandle(headers);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- SearchGroups
-
- Search groups on the server and build a new group array containing
- the matching groups and article lists.
-
- Entry: wind = pointer to group, subject, or article window.
- header = header name.
- pattern = search string.
-
- Exit: function result = error code.
- *newGroupArray = array of matching group records.
- *newNumGroups = number of matching group records.
- ----------------------------------------------------------------------------*/
-
- static OSErr SearchGroups (WindowPtr wind, char *header, char *pattern,
- TGroup ***newGroupArray, short *newNumGroups)
- {
- TWindow **info;
- TWindowKind kind;
- ListHandle theList;
- Cell theCell;
- short index, cellDataLen;
- TGroup **groupArray;
- TGroup theGroup;
- TGroup **theNewGroupArray = nil;
- short theNewNumGroups = 0;
- short numAllocated;
- OSErr err = noErr;
- Boolean done = false;
- Boolean firstTime = true;
- Handle newsgroups = nil;
- long i, j, k, len;
- CStr255 groupName;
- char c;
-
- info = (TWindow**)GetWRefCon(wind);
- kind = (**info).kind;
-
- err = MyNewHandle(100*sizeof(TGroup), &theNewGroupArray);
- if (err != noErr) goto exit;
- numAllocated = 100;
-
- switch (kind) {
- case kGroup:
- theList = (**info).theList;
- groupArray = (**info).groupArray;
- SetPt(&theCell, 0, 0);
- break;
- case kSubject:
- break;
- case kArticle:
- err = FindHeaderHandle((**info).fullText, "Newsgroups", &newsgroups);
- if (err != noErr) goto exit;
- len = MyGetHandleSize(newsgroups);
- i = 0;
- break;
- }
-
- while (!done) {
- switch (kind) {
- case kGroup:
- done = !LGetSelect(true, &theCell, theList);
- if (done) break;
- cellDataLen = 2;
- LGetCell(&index, &cellDataLen, theCell, theList);
- theGroup.nameOffset = (*groupArray)[index].nameOffset;
- theCell.v++;
- break;
- case kSubject:
- done = !firstTime;
- if (done) break;
- firstTime = false;
- theGroup.nameOffset = (**info).groupNameOffset;
- break;
- case kArticle:
- while (true) {
- while (i < len && !isalnum((*newsgroups)[i])) i++;
- done = i >= len;
- if (done) break;
- j = 0;
- while (i < len && j < 256) {
- c = (*newsgroups)[i];
- if (isalnum(c) || c == '.') {
- groupName[j++] = c;
- i++;
- } else {
- break;
- }
- }
- done = j >= 256;
- if (done) break;
- groupName[j] = 0;
- k = FindGroupIndex(groupName);
- if (k != -1) {
- theGroup.nameOffset = (*gFullGroupArray)[k].nameOffset;
- break;
- }
- }
- break;
- }
- if (done) break;
- theGroup.firstMess = theGroup.lastMess = theGroup.numUnread = 0;
- theGroup.unread = nil;
- theGroup.onlyRedrawCount = false;
- err = SearchOneGroup(header, pattern, &theGroup);
- if (err != noErr) goto exit;
- if (theGroup.numUnread != 0) {
- if (theNewNumGroups >= numAllocated) {
- numAllocated += 100;
- err = MySetHandleSize(theNewGroupArray, numAllocated*sizeof(TGroup));
- if (err != noErr) goto exit;
- }
- (*theNewGroupArray)[theNewNumGroups] = theGroup;
- theNewNumGroups++;
- }
- }
-
- MySetHandleSize(theNewGroupArray, theNewNumGroups*sizeof(TGroup));
- *newGroupArray = theNewGroupArray;
- *newNumGroups = theNewNumGroups;
- MyDisposeHandle(newsgroups);
- return noErr;
-
- exit:
-
- DisposeGroupArray(theNewGroupArray, theNewNumGroups);
- MyDisposeHandle(newsgroups);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoSearch
-
- Handle the "Search" command.
-
- Entry: wind = pointer to group, subject, or article window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr DoSearch (WindowPtr wind)
- {
- CStr255 header, pattern;
- TGroup **groupArray = nil;
- short numGroups;
- WindowPtr newWind;
- TWindow **info;
- Str255 title;
- OSErr err = noErr;
- TSavedWindPos pos;
-
- /* Present the search dialog. */
-
- err = DoSearchDialog(header, pattern);
- if (err != noErr) return err;
-
- /* Search the groups. */
-
- err = SearchGroups(wind, header, pattern, &groupArray, &numGroups);
- if (err != noErr) return err;
- if (numGroups == 0) {
- NoteMessageNumber(kStrNoMatches);
- MyDisposeHandle(groupArray);
- return noErr;
- }
-
- /* Create the window. */
-
- GetPString(kStrSearchWindowTitle, title);
- pos.valid = false;
- err = MakeUserGroupWindow(title, groupArray, numGroups, &pos, &newWind);
- if (err != noErr) return err;
- info = (TWindow**)GetWRefCon(newWind);
- (**info).okToCloseIfChanged = true;
- return noErr;
- }
-